﻿using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using Ping.Core;

namespace Ping.App
{
	public abstract class StorageService<T>
	{
		/// <summary>
		/// The filename to save to.
		/// </summary>
		protected abstract string FileName { get; }

		/// <summary>
		/// The list of known types, given to the serializer.
		/// </summary>
		protected virtual Type[] KnownTypes
		{
			get
			{
				return new[]
				       	{
				       		typeof (ServerStatus),
				       		typeof (DnsResult),
				       		typeof (PingResult),
				       		typeof (TracerouteResult),
				       		typeof (GeoResult),
							typeof (GeoDataSet),
				       	};
			}
		}

		protected void Save(T data)
		{
			IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
			IsolatedStorageFileStream file = storage.CreateFile(FileName);

			try
			{
				DataContractSerializer serializer = CreateSerializer();
				serializer.WriteObject(file, data);
			}
			catch
			{
				// Don't leave partial files
				file.Close();
				storage.DeleteFile(FileName);
				throw;
			}
			finally
			{
				file.Close();
			}
		}

		/// <summary>
		/// Restores the settings from disk.
		/// </summary>
		protected T Load()
		{
			IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
			if (!storage.FileExists(FileName))
			{
				return CreateDefault();
			}

			IsolatedStorageFileStream file = storage.OpenFile(FileName, FileMode.Open);
			T ret;

			try
			{
				DataContractSerializer serializer = CreateSerializer();
				ret = (T) serializer.ReadObject(file);
			}
			catch
			{
				// Doesn't really matter: We simply continue without restoring a previous state:
				// we keep the current one...
				ret = CreateDefault();
			}
			finally
			{
				file.Close();
			}

			return ret;
		}

		protected virtual DataContractSerializer CreateSerializer()
		{
			return new DataContractSerializer(typeof (T), KnownTypes);
		}

		protected abstract T CreateDefault();
	}
}